<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Three.js 3D模型展示</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
        canvas {
            display: block;
        }
        #info {
            position: absolute;
            top: 10px;
            width: 100%;
            text-align: center;
            color: white;
            font-family: Arial, sans-serif;
            pointer-events: none;
            z-index: 100;
            text-shadow: 1px 1px 1px black;
        }
        #controls {
            position: absolute;
            bottom: 20px;
            left: 20px;
            background: rgba(0,0,0,0.5);
            padding: 10px;
            border-radius: 5px;
            color: white;
            font-family: Arial, sans-serif;
        }
        button {
            background: #4CAF50;
            border: none;
            color: white;
            padding: 8px 16px;
            margin: 5px;
            border-radius: 4px;
            cursor: pointer;
        }
        button:hover {
            background: #45a049;
        }
    </style>
</head>
<body>
    <div id="info">Three.js 3D模型展示 - 使用鼠标左键旋转，右键平移，滚轮缩放</div>
    <div id="controls">
        <button id="view-front">正视图</button>
        <button id="view-side">侧视图</button>
        <button id="view-top">俯视图</button>
        <button id="toggle-wireframe">切换线框模式</button>
        <button id="toggle-animation">暂停/播放动画</button>
        <button id="toggle-rotation">开启/关闭自动旋转</button>
    </div>

    <!-- 引入Three.js库 -->
    <script src="https://cdn.jsdelivr.net/npm/three@0.132.2/build/three.min.js"></script>
    <!-- 引入OrbitControls控制器 -->
    <script src="https://cdn.jsdelivr.net/npm/three@0.132.2/examples/js/controls/OrbitControls.js"></script>
    <!-- 引入GLTFLoader加载器 -->
    <script src="https://cdn.jsdelivr.net/npm/three@0.132.2/examples/js/loaders/GLTFLoader.js"></script>
    <!-- 引入状态监控器 -->
    <script src="https://cdn.jsdelivr.net/npm/three@0.132.2/examples/js/libs/stats.min.js"></script>
    <!-- 引入RGBELoader加载HDR -->
    <script src="https://cdn.jsdelivr.net/npm/three@0.132.2/examples/js/loaders/RGBELoader.js"></script>
    <!-- 引入拾取辅助工具 -->
    <script src="https://cdn.jsdelivr.net/npm/three@0.132.2/examples/js/interactive/SelectionHelper.js"></script>

    <script>
        // 创建场景、相机和渲染器
        const scene = new THREE.Scene();
        const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
        const renderer = new THREE.WebGLRenderer({ antialias: true });
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.outputEncoding = THREE.sRGBEncoding;
        renderer.toneMapping = THREE.ACESFilmicToneMapping;
        renderer.toneMappingExposure = 1;
        document.body.appendChild(renderer.domElement);

        // // 创建轨道控制器
        const controls = new THREE.OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true; // 启用阻尼效果
        controls.dampingFactor = 0.05;

        // 创建性能监视器
        const stats = new Stats();
        stats.dom.style.position = 'absolute';
        stats.dom.style.top = '0px';
        stats.dom.style.left = '0px';
        document.body.appendChild(stats.dom);

        // 添加光源
        const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
        scene.add(ambientLight);
        
        const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
        directionalLight.position.set(5, 10, 7.5);
        directionalLight.castShadow = true;
        scene.add(directionalLight);

        // 设置阴影贴图大小以提高阴影质量
        directionalLight.shadow.mapSize.width = 2048;
        directionalLight.shadow.mapSize.height = 2048;
        
        // 初始化相机位置
        camera.position.set(3, 2, 5);
        
        // 添加坐标轴辅助工具
        const axesHelper = new THREE.AxesHelper(5);
        scene.add(axesHelper);
        
        // 添加网格地面
        const gridHelper = new THREE.GridHelper(10, 10);
        scene.add(gridHelper);
        
        // 设置背景
        scene.background = new THREE.Color(0x2a2a2a);
        
        // 全局变量
        let model;
        let mixer;
        let clock = new THREE.Clock();
        let animationRunning = true;
        let autoRotate = false;
        
        // 加载GLTF模型
        const loader = new THREE.GLTFLoader();
        loader.load(
            // 这里使用一个公共可用的3D模型 - 机器人模型
            'https://threejs.org/examples/models/gltf/RobotExpressive/RobotExpressive.glb',
            function(gltf) {
                model = gltf.scene;
                
                // 设置模型阴影
                model.traverse(function(node) {
                    if (node.isMesh) {
                        node.castShadow = true;
                        node.receiveShadow = true;
                    }
                });
                
                // 调整模型大小和位置
                model.scale.set(1, 1, 1);
                model.position.set(0, 0, 0);
                
                // 添加模型到场景
                scene.add(model);
                
                // 设置动画混合器
                if (gltf.animations && gltf.animations.length) {
                    mixer = new THREE.AnimationMixer(model);
                    const action = mixer.clipAction(gltf.animations[8]); // 使用"Idle"动画
                    action.play();
                }
                
                // 调整相机以适应模型
                fitCameraToObject(camera, model, controls);
                
                console.log('模型加载成功');
            },
            function(xhr) {
                console.log((xhr.loaded / xhr.total * 100) + '% 已加载');
            },
            function(error) {
                console.error('加载模型时出错:', error);
            }
        );
        
        // 让相机适应模型
        function fitCameraToObject(camera, object, controls) {
            const box = new THREE.Box3().setFromObject(object);
            const center = box.getCenter(new THREE.Vector3());
            const size = box.getSize(new THREE.Vector3());
            
            const maxDim = Math.max(size.x, size.y, size.z);
            const fov = camera.fov * (Math.PI / 180);
            let cameraZ = Math.abs(maxDim / 2 * Math.tan(fov * 2));
            
            cameraZ *= 1.5; // 放大一点以便更好地看到模型
            
            camera.position.set(center.x, center.y, center.z + cameraZ);
            
            // 设置相机看向模型中心
            const minZ = box.min.z;
            const cameraToFarEdge = (minZ < 0) ? -minZ + cameraZ : cameraZ - minZ;
            
            camera.far = cameraToFarEdge * 3;
            camera.updateProjectionMatrix();
            
            if (controls) {
                // 设置控制器目标为模型中心
                controls.target = center;
                controls.update();
            }
        }
        
        // 切换视角函数
        function setFrontView() {
            if (model) {
                const box = new THREE.Box3().setFromObject(model);
                const center = box.getCenter(new THREE.Vector3());
                const size = box.getSize(new THREE.Vector3());
                
                // 设置正视图
                camera.position.set(0, center.y, center.z + size.z * 2);
                controls.target.set(center.x, center.y, center.z);
                controls.update();
            }
        }
        
        function setSideView() {
            if (model) {
                const box = new THREE.Box3().setFromObject(model);
                const center = box.getCenter(new THREE.Vector3());
                const size = box.getSize(new THREE.Vector3());
                
                // 设置侧视图
                camera.position.set(center.x + size.x * 2, center.y, center.z);
                controls.target.set(center.x, center.y, center.z);
                controls.update();
            }
        }
        
        function setTopView() {
            if (model) {
                const box = new THREE.Box3().setFromObject(model);
                const center = box.getCenter(new THREE.Vector3());
                const size = box.getSize(new THREE.Vector3());
                
                // 设置俯视图
                camera.position.set(center.x, center.y + size.y * 2, center.z);
                controls.target.set(center.x, center.y, center.z);
                controls.update();
            }
        }
        
        // 切换线框模式
        function toggleWireframe() {
            if (model) {
                model.traverse(function(node) {
                    if (node.isMesh) {
                        node.material.wireframe = !node.material.wireframe;
                    }
                });
            }
        }
        
        // 切换动画播放状态
        function toggleAnimation() {
            animationRunning = !animationRunning;
        }
        
        // 切换自动旋转
        function toggleRotation() {
            autoRotate = !autoRotate;
            controls.autoRotate = autoRotate;
        }
        
        // 事件监听
        document.getElementById('view-front').addEventListener('click', setFrontView);
        document.getElementById('view-side').addEventListener('click', setSideView);
        document.getElementById('view-top').addEventListener('click', setTopView);
        document.getElementById('toggle-wireframe').addEventListener('click', toggleWireframe);
        document.getElementById('toggle-animation').addEventListener('click', toggleAnimation);
        document.getElementById('toggle-rotation').addEventListener('click', toggleRotation);
        
        // 模型拾取
        const raycaster = new THREE.Raycaster();
        const mouse = new THREE.Vector2();
        
        renderer.domElement.addEventListener('click', onModelClick, false);
        
        function onModelClick(event) {
            // 计算鼠标在归一化设备坐标中的位置
            mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
            mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
            
            // 从相机通过鼠标位置发出射线
            raycaster.setFromCamera(mouse, camera);
            
            if (model) {
                // 检查射线是否与模型的任何部分相交
                const intersects = raycaster.intersectObject(model, true);
                
                if (intersects.length > 0) {
                    const selectedObject = intersects[0].object;
                    
                    // 高亮选中的部分
                    if (selectedObject.material) {
                        // 克隆材质以避免影响其他使用相同材质的部分
                        if (!selectedObject.originalMaterial) {
                            selectedObject.originalMaterial = selectedObject.material.clone();
                        }
                        
                        // 重置所有模型部分的材质
                        model.traverse(function(node) {
                            if (node.isMesh && node.originalMaterial) {
                                node.material = node.originalMaterial.clone();
                            }
                        });
                        
                        // 设置选中部分的材质
                        const highlightMaterial = selectedObject.originalMaterial.clone();
                        highlightMaterial.emissive = new THREE.Color(0xff9900);
                        highlightMaterial.emissiveIntensity = 0.5;
                        selectedObject.material = highlightMaterial;
                        
                        console.log('选中模型部分:', selectedObject.name || '未命名部分');
                    }
                }
            }
        }
        
        // 处理窗口大小调整
        window.addEventListener('resize', function() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
        }, false);
        
        // 动画循环
        function animate() {
            requestAnimationFrame(animate);
            
            // 更新控制器
            controls.update();
            
            // 更新动画
            const delta = clock.getDelta();
            if (mixer && animationRunning) {
                mixer.update(delta);
            }
            
            // 更新性能监视器
            stats.update();
            
            // 渲染场景
            renderer.render(scene, camera);
        }
        
        animate();
    </script>
</body>
</html> 